package com.tcl.logoidentify.web.api;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.google.common.primitives.Longs;
import com.tcl.logoidentify.commons.Assert;
import com.tcl.logoidentify.commons.ByteUtils;
import com.tcl.logoidentify.commons.ChannelsInfo;
import com.tcl.logoidentify.commons.ConfigUtils;
import com.tcl.logoidentify.commons.FPCache;
import com.tcl.logoidentify.commons.FPCacheFactory;
import com.tcl.logoidentify.commons.ServletUtils;
import com.tcl.logoidentify.exception.RestErrorCode;

@WebServlet("/api/v1/logoidentify/search")
public class Search extends HttpServlet {
	private final static Logger LOGGER = LoggerFactory.getLogger(Search.class);
	private static final long serialVersionUID = 1L;
	private String black_fingerprint = "_____________________________w";
	private static final int SEARCH_METHOD = Integer.valueOf(ConfigUtils.$("search_method", "1"));
	private static final String RESULT_UNKNOW = "{\"error_code\":\"1000\",\"channel_name\":\"unknown\",\"channel_code\":\"unknown\"}";

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		long start = System.currentTimeMillis();

		response.setContentType("text/json;charset=UTF-8");

		String app_name = request.getParameter("app_name");
		String inputsource_type = request.getParameter("inputsource_type");
		String channel_name = request.getParameter("channel_name");
		String user_id = request.getParameter("user_id");
		String client_fingerprint = request.getParameter("client_fingerprint");
		String create_times = request.getParameter("create_times");
		String dnum = request.getParameter("dnum");
		try {
			validationHttpRequestParams(inputsource_type, user_id, client_fingerprint, create_times);
		} catch (IllegalArgumentException e) {
			response.getWriter().write(e.getMessage());
			return;
		}
		String client_ip = ServletUtils.getIpByRequest(request);
		byte[] fingerprint = Base64.decodeBase64(client_fingerprint);
		int clientCreateTimes = Short.valueOf(create_times);
		byte[] matchcode = null;
		if (fingerprint.length > 16) {
			matchcode = SEARCH_METHOD == 1 ? FPCacheFactory.FPCACHE_88.forkJoinSearch(fingerprint) : FPCacheFactory.FPCACHE_88.search(fingerprint);
		} else {
			matchcode = SEARCH_METHOD == 1 ? FPCacheFactory.FPCACHE_64.forkJoinSearch(fingerprint) : FPCacheFactory.FPCACHE_64.search(fingerprint);
		}
		// JSONObject loginfo = new JSONObject();
		// loginfo.put("app_name", app_name);
		// loginfo.put("inputsource_type", inputsource_type);
		// loginfo.put("user_id", user_id);
		// loginfo.put("client_fingerprint", client_fingerprint);
		// loginfo.put("create_times", create_times);

		if (matchcode != null) {
			int ch_id = ByteUtils.byte2Short(matchcode, 12);
			int serverCreateTimes = (matchcode[14] << 8 ^ matchcode[15]);
			String[] ch_info = ChannelsInfo.getChannelInfo(ch_id);
			String ch_name = ch_info[1];
			String ch_code = ch_info[2];
			long netty_server_time = Longs.fromBytes(matchcode[20], matchcode[21], matchcode[22], matchcode[23], matchcode[24], matchcode[25], matchcode[26], matchcode[27]);
			long time_diff = (netty_server_time - serverCreateTimes) - (System.currentTimeMillis() - clientCreateTimes);

			JSONObject res = new JSONObject();
			res.put("error_code", RestErrorCode.REST_SUCCESS_CODE);
			res.put("channel_name", ch_name);
			res.put("channel_code", ch_code);
			res.put("channel_memo", "");
			res.put("time_diff", time_diff);

			// loginfo.put("channel_name", ch_name);
			// loginfo.put("channel_code", ch_code);
			// loginfo.put("time_diff", time_diff);

			response.getWriter().write(res.toJSONString());

		} else {
			response.getWriter().write(RESULT_UNKNOW);
		}
		long end = System.currentTimeMillis();
		// loginfo.put("duration", end-start);
		// LOGGER.debug(loginfo.toJSONString());

	}

	public void validationHttpRequestParams(String inputsource_type, String user_id, String client_fingerprint, String create_times) {

		Assert.notEmpty(user_id, createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_USERID_REQUIRED_ERROR_MSG));
		Assert.notEmpty(client_fingerprint, createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_CLIENTFINGERPRINT_REQUIRED_ERROR_MSG));
		Assert.notEmpty(create_times, createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_CREATETIMES_REQUIRED_ERROR_MSG));
		Assert.notEmpty(inputsource_type, createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_INPUTSOURCETYPE_REQUIRED_ERROR_MSG));
		Assert.notEmpty(inputsource_type, createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_INPUTSOURCETYPE_REQUIRED_ERROR_MSG));

		// create_times类型校验
		try {
			Short.valueOf(create_times);
		} catch (NumberFormatException e) {
			LOGGER.error(RestErrorCode.REST_CREATETIMES_ERROR_MSG);
			throw new IllegalArgumentException(createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_CREATETIMES_ERROR_MSG));
		}
		// 指纹长度校验
		int length = Base64.decodeBase64(client_fingerprint).length;
		if (length != 22) {
			LOGGER.error(RestErrorCode.REST_CLIENTFINGERPRINT_ERROR_MSG);
			throw new IllegalArgumentException(createErrMsg(RestErrorCode.REST_PARAMETER_ERROR_CODE, RestErrorCode.REST_CLIENTFINGERPRINT_ERROR_MSG));
		}
		// 黑屏校验
		Assert.notTrue(black_fingerprint.equals(client_fingerprint), createErrMsg(RestErrorCode.REST_FINGERPRINT_ERROR_CODE, RestErrorCode.REST_FINGERPRINT_ERROR_MSG));

	}

	private String createErrMsg(int errorCode, String errorMsg) {
		JSONObject errMsg = new JSONObject();
		errMsg.put("error_code", errorCode);
		errMsg.put("error_msg", errorMsg);
		return errMsg.toString();
	}
}
